Shallow and Deep copying of mutable objects

…or how to copy lists and nested lists [same for dictionaries]?

The difference between shallow and deep copying is only
relevant for compound objects, i.e. objects containing other objects,
like lists or class instances.

Simple objects

x = 3
y = x
print(id(x), id(y))   # 9251744 9251744

y = 4                 # y will receive a separate memory location
print(id(x), id(y))   # 9251744 9251776
print(x,y)            # 3 4

Copying a List

lst1 = ['a','b',['ab','ba']]
lst2 = lst1
print(id(lst1), id(lst2))  # 33776264 33776264

lst2[0] = 'c'
print(lst2)   # ['c', 'b', ['ab', 'ba']]
print(lst1)   # ['c', 'b', ['ab', 'ba']]       # <--- !!!
print(id(lst1), id(lst2))  # 33776264 33776264

Copy with the Slice Operator

lst1 = ['a','b',['ab','ba']]
lst2 = lst1[:]
print(id(lst1), id(lst2))  # 30565000 66829000

lst2[0] = 'c'
print(lst2)   # ['c', 'b', ['ab', 'ba']]
print(lst1)   # ['a', 'b', ['ab', 'ba']]   # <-- OK

lst2[2][1] = 'd'
print(lst2)   # ['c', 'b', ['ab', 'd']]
print(lst1)   # ['a', 'b', ['ab', 'd']]    # <--- !!!

Using the Method deepcopy from the Module copy

from copy import deepcopy

lst1 = ['a','b',['ab','ba']]
lst2 = deepcopy(lst1)
print(id(lst1), id(lst2))   # 33907272 34404552
print(lst1)   # ['a', 'b', ['ab', 'ba']]
print(lst2)   # ['a', 'b', ['ab', 'ba']]

lst2[0] = 'c'
lst2[2][1] = 'd'
print(lst2)    # ['c', 'b', ['ab', 'd']]
print(lst1)    # ['a', 'b', ['ab', 'ba']]   <--- OK